home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 98
/
Skunkware 98.iso
/
src
/
mail
/
pine3.96.tar.gz
/
pine3.96.tar
/
pine3.96
/
pine
/
osdep
/
dosextra
< prev
next >
Wrap
Text File
|
1996-06-06
|
13KB
|
556 lines
#line 2 "osdep/dosextra"
/*
* map the ftruncate call into DOS' chsize
*/
int
ftruncate(fd, size)
int fd;
long size;
{
return(chsize(fd, size));
}
#ifndef OS2
/*
* have_ printer - use BIOS int 0x17 to get a system equipment list
* returning whether or not there's a printer
*/
have_printer()
{
union REGS rg;
int86(0x11, &rg, &rg); /* what's there ? */
return(rg.x.ax & 0xc000); /* any printers ? */
}
/*
* printer_status - get printer status using BIOS printer services (int 17h)
* return 0 if printer responds bad status otherwise.
*/
unsigned short printer_ready()
{
union REGS rg;
if(!have_printer()) /* bother to get stat ? */
return(0xffff);
rg.h.ah = 0x02; /* get printer status */
rg.x.dx = 0; /* which printer */
int86(0x17, &rg, &rg); /* do it */
return(rg.h.ah & ~(0xd6)); /* 0x10, 0x40 & 0x80 are OK */
/* 0x02 and 0x04 are ignored */
}
/*
* p_printer_error - given a a byte of error code, return the string
* corresponding to it.
*/
char *p_printer_error(err)
unsigned short err;
{
if(err == 0xffff)
return("No printer found");
else if(err & 0x01)
return("Status 1: Time out (on line?)");
else if(err & 0x08)
return("Status 8: I/O error");
else if(err & 0x20)
return("Status 32: Out of paper ");
else if(err & 0x40 || err & 0x80 || err & 0x10)
/* ACK from printer or printer NOT busy or printer selected */
return("");
else
return("Weird printer status");
}
/*
* send_printer - write a byte to the printer returning status
*/
int send_printer(c)
char c;
{
union REGS rg;
rg.h.ah = 0; /* service 0: send a byte */
rg.h.al = c; /* which byte */
rg.x.dx = 0; /* which printer */
int86(0x17, &rg, &rg); /* do it */
return(rg.h.ah & ~(0xd6)); /* 0x10, 0x40 & 0x80 are OK */
/* 0x02 and 0x04 are ignored */
}
/*
* coreleft - returns the amount of core memory currently available
*/
long
coreleft()
{
#ifdef _WINDOWS
return (GetFreeSpace (0));
#else
long ramfree = 0L;
register int i = 0, j;
static unsigned segs[10];
union REGS r;
struct SREGS s;
while(1){
r.h.ah = 0x48; /* DOS alloc a paragraph */
r.x.bx = 0x0001; /* grab 1 paragraph (16 bytes) */
intdos(&r, &r);
if(r.x.cflag){ /* carry flag set, no more core */
for(j=0;j<i;j++){
r.h.ah = 0x49; /* DOS free alloc'd core */
s.es = segs[j]; /* segment to free */
intdosx(&r, &r, &s);
}
return(ramfree*16L);
}
else
segs[i] = r.x.ax; /* remember the sigment */
r.h.ah = 0x4a; /* DOS resize alloc'd core */
r.x.bx = 0xffff; /* grab the biggest we can */
s.es = segs[i]; /* segment to resize */
intdosx(&r, &r, &s);
if(r.x.cflag){
r.h.ah = 0x4a; /* DOS resize alloc'd core */
s.es = segs[i]; /* segment to resize */
intdosx(&r, &r, &s);
ramfree += r.x.bx;
}
else
ramfree += 0xffff;
i++;
}
#endif
}
#endif
/*
* OS unique c-client calls and such.
*/
/*
* zone_offset - print the time zone offset in local differential
* form : hours+minutes (HHMM)
*/
void
zone_offset(buf)
char *buf;
{
struct timeb tb;
ftime(&tb);
sprintf(buf, "%02.2u%02.2u", tb.timezone/60, tb.timezone%60);
}
#ifndef OS2
/*
* Special hook so externally we can avoid copying from one file to
* another. It's quite a hack, and not exactly clear, but does help
* performance-wise.
*/
FILE *append_file = NULL;
/*
* dos_gets - c-client callback for mail_fetchbody to use when receiving
* a message text too large for free mem (see mailview.c).
*/
char *dos_gets (f, stream, size)
readfn_t f;
void *stream;
unsigned long size;
{
char tmp[MAILTMPLEN+1];
unsigned long j = 0L;
extern unsigned long gets_bytes;
if(!append_file){
char es[128];
/* post error message, dump the text in the bit bucket */
mm_log("dos_gets: NO FILE HANDLE TO APPEND",ERROR);
return(NULL);
}
while(size -= j){
(*f) (stream, j = min ((long) MAILTMPLEN, size), tmp);
gets_bytes += j;
#ifndef _WINDOWS
win_multiplex();
#endif
if(fwrite(tmp, sizeof(char), (size_t)j, append_file) != j){
/* problem writing temp file! bail gracefully */
sprintf(tmp,"Error getting message: %s", error_description(errno));
mm_log(tmp, ERROR);
return(NULL);
}
}
return(cpystr("programmer botch: data on disk"));
}
/*
* ******* DOS Cache Manager *******
*
* Each mail stream has associated with it a cache of mail elements
* ("elt" in c-client parlance). This can get too ponderous slog around
* in the 640K *MAX* that DOS allows, so the idea is to manager some number
* of them in core and page the rest out to disk. ALL CACHE ACCESS IN
* C-CLIENT MUST TO GO THRU THE mailcache() FUNCTION!!
*
*/
/*
* CacheBlock_SIZE: number of elt's cached in core at any one time
*/
#define CB_SIZE (20L)
/*
* Meta cache structure. Used by dos_cache to hold either short or long
* elt's and a flag reporting if the entry's been accessed/used or not.
*/
typedef struct metacache {
short use; /* cache slot in use flag */
union {
MESSAGECACHE mc;
LONGCACHE lc;
} cachel; /* access to cache elements */
} METACACHE;
/*
* Master DOS cache structure. Every mail stream gets one, and has it
* until it dies. c-client worries about freeing this with a CH_INIT.
*/
typedef struct doscache {
FILE *dcf; /* DOS cache file pointer */
char *name; /* DOS cache file's name */
long cbase; /* index of array in slot 1 of block */
METACACHE mcb[CB_SIZE]; /* meta cache block */
} DOSCACHE;
/*
* dcreadb - dos cache read block; given a stream, read a new block
* of cache entries into core. Doscache's cbase field
* describes where to start loading.
*/
void dcreadb(cache)
DOSCACHE *cache;
{
size_t n;
if(fseek(cache->dcf, cache->cbase * sizeof(METACACHE), SEEK_SET))
fatal("ran off end of dos cache file in dcreadb");
n = fread((void *)&cache->mcb[0],sizeof(METACACHE),
(size_t)CB_SIZE,cache->dcf);
if(n != CB_SIZE)
fatal("Can't read cache block in from disk");
}
/*
* dcwriteb - dos cache write block; given a stream, write the current
* block of cache entries to disk. Guaranteed write, or fatal.
*/
void dcwriteb(cache)
DOSCACHE *cache;
{
size_t n;
if(fseek(cache->dcf, cache->cbase * sizeof(METACACHE), SEEK_SET))
fatal("ran off end of dos cache file in dcwriteb");
n = fwrite(&cache->mcb[0], sizeof(METACACHE), (size_t)CB_SIZE, cache->dcf);
if(n != CB_SIZE)
fatal("Can't write cache block to from disk");
}
/*
* dchit - make sure metacache entry for msgno is in core, if not,
* write current block and read in new one that contains it.
*/
void dchit(cache, msgno)
DOSCACHE *cache;
long msgno;
{
long i = msgno - 1; /* index of msgno's elt */
size_t n;
if(msgno <= 0)
fatal("bogus msgno passed to dchit");
if(i >= cache->cbase && i < cache->cbase + CB_SIZE)
return; /* everything's okey dokey */
dcwriteb(cache); /* roll out the current block */
cache->cbase = (i/CB_SIZE) * CB_SIZE;
dcreadb(cache); /* roll in the new block */
}
/*
* dcget - dos cache get; given a stream and a message number in it,
* return a pointer to the cache entry associated with it.
*/
METACACHE *dcget(stream, msgno)
MAILSTREAM *stream;
long msgno;
{
int i;
DOSCACHE *dc = (DOSCACHE *)stream->cache.c;
dchit(dc, msgno); /* correct block in core? */
i = (int)((msgno-1)%CB_SIZE); /* offset of entry in block */
if(!dc->mcb[i].use){ /* new cache entry! */
memset((void *)&dc->mcb[i], 0, sizeof(METACACHE));
dc->mcb[i].use = 1; /* mark entry as accessed */
if(stream->scache){
dc->mcb[i].cachel.mc.lockcount = 1;
dc->mcb[i].cachel.mc.msgno = msgno;
}
else{
dc->mcb[i].cachel.lc.elt.lockcount = 1;
dc->mcb[i].cachel.lc.elt.msgno = msgno;
dc->mcb[i].cachel.lc.env = NULL;
dc->mcb[i].cachel.lc.body = NULL;
}
}
return(&dc->mcb[i]);
}
/*
* dos_cache - c-client callback used to manage cached elt's and
* envelopes. (see ../c-client/mail.c)
*/
void *dos_cache(stream, msgno, op)
MAILSTREAM *stream;
long msgno;
long op;
{
size_t n;
void *ret = NULL;
long i = msgno - 1;
unsigned long j = stream->cachesize;
METACACHE ctmp;
DOSCACHE *dtmp = (DOSCACHE *)stream->cache.c;
switch ((int) op) { /* what function? */
case CH_INIT: /* initialize cache */
if (stream->cachesize) { /* flush old cache contents */
/*
* WARNING: if lock counts are ever important, this will
* have to become a loop counting down the
* cachesize and calling something like
* mail_free_elt() for each one!
*/
fclose(dtmp->dcf); /* should auto blast tmpfile */
if(dtmp->name){
unlink(dtmp->name);
free(dtmp->name);
dtmp->name = NULL;
}
fs_give((void **)&stream->cache.c);
stream->cachesize = 0;
}
break;
case CH_SIZE: /* (re-)size the cache */
if (msgno > j) { /* do nothing if size adequate */
/*
* TUNING POTENTIAL: the const 4 below could be tweeked
*/
while(msgno > stream->cachesize)
stream->cachesize += (CB_SIZE * 4);
if (stream->cache.c == NULL){
stream->cache.c = (void *)fs_get(sizeof(DOSCACHE));
memset(stream->cache.c, 0, sizeof(DOSCACHE));
dtmp = (DOSCACHE *)stream->cache.c;
if(!dtmp->name)
dtmp->name = temp_nam(NULL, "pi");
/*
* Can't use tmpfile() as MSC's library call won't
* observe TMP or TEMP env vars. Wonders never cease.
*/
if((dtmp->dcf = (void *)fopen(dtmp->name, "w+b")) == NULL){
sprintf(tmp_20k_buf,"Can't open DOS cache: %s",dtmp->name);
fatal(tmp_20k_buf);
}
for(j = 0; j < stream->cachesize; j += CB_SIZE){
dtmp->cbase = j;
dcwriteb(dtmp);
}
dtmp->cbase = 0;
}
else{
/* init new entries */
fseek(dtmp->dcf, j * sizeof(METACACHE), SEEK_SET);
memset((void *)&ctmp, 0, sizeof(METACACHE));
for(;j < stream->cachesize; j++){
n = fwrite((void *)&ctmp,sizeof(METACACHE),1,dtmp->dcf);
if(n != 1L)
fatal("Cache init failed on fwrite");
}
}
}
break;
case CH_ELT: /* return elt */
case CH_MAKEELT: /* short elt, make if necessary */
case CH_LELT: /* return long elt */
case CH_MAKELELT: /* long elt, make if necessary */
ret = (stream->scache) ? (void *) &dcget(stream, msgno)->cachel.mc
: (void *) &dcget(stream, msgno)->cachel.lc;
break;
case CH_FREE: /* free (l)elt */
/*
* SEE WARNING ABOVE! if we ever need lock counts
* this should call an appropriate mail_free_XXX-like
* function.
*/
dcget(stream, msgno)->use = 0;
break;
case CH_EXPUNGE: /* expunge cache slot */
{ /* slide down remainder of cache */
METACACHE *dc_copy=(METACACHE *)fs_get(sizeof(METACACHE));
/*
* OPTIMIZE: this could be made a little more efficient by using offset
* into the current block in memory, and copying blocks of
* elt's at a time rather than individually.
*/
for (i = msgno+1; i <= stream->nmsgs; ++i){
memcpy((void *)dc_copy,
(void *)dcget(stream, i),
sizeof(METACACHE));
if(stream->scache)
dc_copy->cachel.mc.msgno = i - 1L;
else
dc_copy->cachel.lc.elt.msgno = i - 1L;
memcpy((void *)dcget(stream, i-1),
(void *)dc_copy,
sizeof(METACACHE));
}
fs_give((void **)&dc_copy);
memset((void *)dcget(stream, stream->nmsgs),
0,
sizeof(METACACHE));
}
break;
default:
fatal ("Bad dos_cache op");
break;
}
return ret;
}
/*
* ***** FOR DEBUGGING *****
*/
void dumpmetacache(stream)
MAILSTREAM *stream;
{
FILE *fp;
long i;
size_t n;
METACACHE ce;
DOSCACHE *dp = (DOSCACHE *)stream->cache.c;
if((fp=fopen("\\tmp\\cache.out","a")) == NULL)
return;
if(!stream->cache.c){
fprintf(fp,"NO CACHE ASSOCIATED WITH STREAM!!!\n");
}
else{
fprintf(fp,"****** cache has %ld entries (%d element blocks)\n",
stream->cachesize, CB_SIZE);
fprintf(fp,"Those in core are:\n");
for(i=0; i < CB_SIZE; i++){
fprintf(fp," %d) ", i+1);
if(!dp->mcb[i].use){
fprintf(fp,"EMPTY\n");
}
else{
fprintf(fp,"# %ld, lock = %d, size = %ld\n",
dp->mcb[i].cachel.mc.msgno,
dp->mcb[i].cachel.mc.lockcount,
dp->mcb[i].cachel.mc.rfc822_size);
}
}
fprintf(fp,"Those on disk are:\n");
fseek(dp->dcf, 0L, SEEK_SET);
for(i=0; i < stream->cachesize; i++){
fprintf(fp," %d) ", i+1);
n = fread(&ce, sizeof(METACACHE), 1, dp->dcf);
if(n != 1){
fprintf(fp,"PROBLEM READING ENTRY!!!\n");
break;
}
if(!ce.use){
fprintf(fp,"EMPTY\n");
}
else{
fprintf(fp,"# %ld, lock = %d, size = %ld\n",
ce.cachel.mc.msgno,
ce.cachel.mc.lockcount,
ce.cachel.mc.rfc822_size);
}
}
}
fclose(fp);
}
#ifndef _WINDOWS
/*
*
*/
unsigned
alarm(t)
unsigned t;
{
}
#endif
#endif